﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using DeepZoomPivotConstructor.VisualLib.Hotspots;
using System.IO;

namespace DeepZoomPivotConstructor.VisualLib
{
    /// <summary>
    /// A utility visual. It allows you to add title text at the top, and a background
    /// and will put the containing visual inside it, given the various parameters.
    /// </summary>
    public class VisualTitleAndBackground : Visual
    {
        /// <summary>
        /// Hold onto the subject that we need to track.
        /// </summary>
        private Visual Subject { get; set; }

        /// <summary>
        /// Z level we should put the background at, minus 1
        /// Makes it easy to call IncZLevel on this thing.
        /// </summary>
        private int BackgroundZLevel { get; set; }

        private DirectoryInfo _imageWritingDirectory;

        /// <summary>
        /// Get/Set the directory where we will write generated temp files
        /// </summary>
        public DirectoryInfo ImageWritingDirectory
        {
            get { return _imageWritingDirectory; }
            set
            {
                _imageWritingDirectory = value;
                UpdateLayout();
            }
        }

        /// <summary>
        /// Creates the visual with the main stuff that will be shown (and the title around the edges).
        /// </summary>
        /// <param name="subjectVisual"></param>
        public VisualTitleAndBackground(Visual subjectVisual, DirectoryInfo tempDir = null)
        {
            if (subjectVisual == null)
            {
                throw new ArgumentException("Can't pass null for the visual", "subjectVIsual");
            }
            Subject = subjectVisual;
            Subject.IncZIndex();

            BackgroundZLevel = Subject.ZIndex - 2;

            ///
            /// Copy over the info
            /// 

            Info = Subject.Info;

            ///
            /// Set some defaults
            /// 

            XBoarder = 0.2;
            YBoarder = 0.2;
            DPI = 150;
            BackgroundColor = Color.Gray;

            ///
            /// Temp directory setting!
            /// 

            _imageWritingDirectory = tempDir;

            ///
            /// do the initial setting!
            /// 

            UpdateLayout();
        }

        class TextInfo
        {
            public double height { get; set; }
            public string text { get; set; }
            public HotSpotActionBase action { get; set; }
        }
        private List<TextInfo> TextToPlace = new List<TextInfo>();

        /// <summary>
        /// Append a new line of text in the header region.
        /// </summary>
        /// <param name="textHeight"></param>
        /// <param name="text"></param>
        public void Add(double textHeight, string t)
        {
            TextToPlace.Add(new TextInfo() { height = textHeight, text = t });
            UpdateLayout();
        }

        /// <summary>
        /// Add a new line of text which will do something when clicked.
        /// </summary>
        /// <param name="textHeight"></param>
        /// <param name="t"></param>
        /// <param name="action"></param>
        public void Add(double textHeight, string t, HotSpotActionBase a)
        {
            TextToPlace.Add(new TextInfo() { height = textHeight, text = t, action = a });
            UpdateLayout();
        }

        /// <summary>
        /// Called when something about the layout has been
        /// changed.
        /// </summary>
        private void UpdateLayout()
        {
            if (Subject == null)
            {
                return;
            }

            ///
            /// Given the text we have to track, calc how high the total background should be.
            /// 

            var totalTextHeight = (from t in TextToPlace
                                   select t.height).Sum();
            if (totalTextHeight > 0)
            {
                totalTextHeight += YBoarder;
            }

            ///
            /// We have all the basics. Create teh background now, and put it's Z where the
            /// original subject would have been.
            /// 

            var subjectBB = Subject.VisualBoundingBox;
            VisualBitmapImage background = new VisualBitmapImage(subjectBB.Width + XBoarder * 2.0, subjectBB.Height + YBoarder * 2.0 + totalTextHeight, DPI, BackgroundColor);
            background.IncZIndex(BackgroundZLevel);
            if (ImageWritingDirectory != null)
            {
                background.ImageWritingDirectory = ImageWritingDirectory;
            }

            ///
            /// Add the text and any associated hot spots
            /// 

            GrandHolder = new VisualHolder();
            double ypos = YBoarder;
            foreach (var t in TextToPlace)
            {
                background.AddText(XBoarder, ypos, t.height, t.text);
                if (t.action != null)
                {
                    VisualHotSpot hs = new VisualHotSpot(subjectBB.Width, t.height)
                    {
                        t.action
                    };
                    hs.IncZIndex(BackgroundZLevel);
                    GrandHolder.AddImage(hs);
                }
                ypos += t.height;
            }

            ///
            /// Put the background and the subject material in there now.
            /// 

            Subject.XPosition = XBoarder;
            Subject.YPosition = YBoarder + totalTextHeight;
            GrandHolder.AddImage(Subject);

            GrandHolder.AddImage(background);
        }

        /// <summary>
        /// The holder that actually will end up holding everything!
        /// </summary>
        private VisualHolder GrandHolder = null;

        /// <summary>
        /// Width of the visual
        /// </summary>
        public override double Width
        {
            get { return GrandHolder.Width; }
        }

        /// <summary>
        /// Height of the visual
        /// </summary>
        public override double Height
        {
            get { return GrandHolder.Height; }
        }

        /// <summary>
        /// get/set X position of the title/background whole thing.
        /// </summary>
        public override double XPosition
        {
            get
            {
                return GrandHolder.XPosition;
            }
            set
            {
                GrandHolder.XPosition = value;
            }
        }

        /// <summary>
        /// Get/set the y position of the whole thing.
        /// </summary>
        public override double YPosition
        {
            get
            {
                return GrandHolder.YPosition;
            }
            set
            {
                GrandHolder.YPosition = value;
            }
        }

        /// <summary>
        /// Scale the visual by some amount
        /// </summary>
        /// <param name="factor"></param>
        public override void Scale(double factor)
        {
            GrandHolder.Scale(factor);
        }

        /// <summary>
        /// Change the z index of this whole thing
        /// </summary>
        /// <param name="delta"></param>
        public override void IncZIndex(int delta)
        {
            GrandHolder.IncZIndex(delta);
        }

        /// <summary>
        /// Return the z index
        /// </summary>
        public override int ZIndex
        {
            get { return GrandHolder.ZIndex; }
        }

        /// <summary>
        /// Returns the nodes of everything!
        /// </summary>
        public override List<SceneGraphSceneNode> SGNodeList
        {
            get { return GrandHolder.SGNodeList; }
        }

        private double _xboarder = 0.0;
        /// <summary>
        /// get/set How much should we put on left and right (indent)
        /// </summary>
        public double XBoarder
        {
            get { return _xboarder; }
            set { _xboarder = value; UpdateLayout(); }
        }

        private double _yboarder = 0.0;
        /// <summary>
        /// Get/set how  much we sould put on top and bottom (indent)
        /// </summary>
        public double YBoarder
        {
            get { return _yboarder; }
            set { _yboarder = value; UpdateLayout(); }
        }

        private int _dpi = 0;
        /// <summary>
        /// Get/set the DPI for the background image rendering
        /// </summary>
        public int DPI
        {
            get {return _dpi;}
            set { _dpi = value; UpdateLayout(); }
        }

        private Color _backgroundColor = Color.Black;

        /// <summary>
        /// Get/Set the color for the background rendering
        /// </summary>
        public Color BackgroundColor
        {
            get { return _backgroundColor; }
            set { _backgroundColor = value; UpdateLayout(); }
        }

        /// <summary>
        /// Returns somethign that will walk through all of our visuals!
        /// </summary>
        /// <returns></returns>
        public override IEnumerator<Visual> GetEnumerator()
        {
            return GrandHolder.GetEnumerator();
        }

    }
}
